package com.zxmzy.scaffold.cardview

import android.content.Context
import android.graphics.*
import android.text.TextUtils
import android.util.AttributeSet
import android.view.View
import android.widget.FrameLayout
import androidx.annotation.AttrRes
import androidx.annotation.ColorInt
import kotlin.math.abs

/**
 * @author zhangxiaoming
 * @date 2023/4/20
 * @description
 */
class ShadowLayout : FrameLayout {
    @ColorInt
    private var mShadowColor = DEFAULT_SHADOW_COLOR //阴影颜色
    private var mShadowRadius = 0f // 阴影发散距离 blur
    private var mDx = 0f // x轴偏移距离
    private var mDy = 0f //  y轴偏移距离
    private var mCornerRadius = 0f //  圆角半径

    @ColorInt
    private var mBorderColor = 0 // 边框颜色
    private var mBorderWidth = 0f //边框宽度
    private var mShadowSides = 0 // 控制四边是否显示阴影
    private var mPaint: Paint? = null // 全局画笔
    private var mHelpPaint: Paint? = null
    private val mPath = Path() // 全局Path
    private var mXfermode: PorterDuffXfermode? = null // 合成模式
    private var mContentRF: RectF? = null // 视图内容区域的RectF实例
    private var mBorderRF: RectF? = null // 视图边框的RectF实例

    companion object {
        private const val FLAG_SIDES_TOP = 1
        private const val FLAG_SIDES_RIGHT = 2
        private const  val FLAG_SIDES_BOTTOM = 4
        private const  val FLAG_SIDES_LEFT = 8
        private const  val FLAG_SIDES_ALL = 15
        private const  val DEFAULT_SHADOW_COLOR = Color.BLACK
        private const  val DEFAULT_BORDER_COLOR = Color.RED
        private const  val DEBUG = false
    }

    constructor(context: Context) : super(context) {
        init()
    }

    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
        initAttrs(context, attrs)
        init()
    }

    constructor(context: Context, attrs: AttributeSet?, @AttrRes defStyleAttr: Int) : super(
        context,
        attrs,
        defStyleAttr
    ) {
        initAttrs(context, attrs)
        init()
    }

    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        mContentRF = RectF(
            paddingLeft.toFloat(), paddingTop.toFloat(), (w - paddingRight).toFloat(),
            (h - paddingBottom).toFloat()
        )
        //以边框宽度的三分之一，微调边框绘制位置，以在边框较宽时得到更好的视觉效果
        val bw = mBorderWidth / 3
        if (bw > 0) {
            mBorderRF = RectF(
                mContentRF!!.left + bw,
                mContentRF!!.top + bw,
                mContentRF!!.right - bw,
                mContentRF!!.bottom - bw
            )
        }
    }

    override fun dispatchDraw(canvas: Canvas?) {
        if (canvas == null) return
        helpGreenCurtain(canvas, DEBUG)
        //绘制阴影
        //绘制阴影
        drawShadow(canvas)
        //绘制子View
        //绘制子View
        drawChild(canvas)
        //绘制边框
        //绘制边框
        drawBorder(canvas)
    }

    private fun drawShadow(canvas: Canvas) {
        canvas.save()

        mPaint?.setShadowLayer(mShadowRadius, mDx, mDy, mShadowColor)
        canvas.drawRoundRect(mContentRF!!, mCornerRadius, mCornerRadius, mPaint!!)
        utilReset(mPaint!!, null, 0)

        canvas.restore()
    }

    private fun drawBorder(canvas: Canvas) {
        mBorderRF?.let {
            canvas.save()
            mPaint?.let {
                it.strokeWidth = mBorderWidth
                it.style = Paint.Style.STROKE
                it.color = mBorderColor
            }
            canvas.drawRoundRect(mContentRF!!, mCornerRadius, mCornerRadius, mPaint!!)
            utilReset(mPaint!!, null, 0)
            canvas.restore()
        }
    }

    private fun drawChild(canvas: Canvas) {
        canvas.saveLayer(
            0f,
            0f,
            canvas.width.toFloat(),
            canvas.height.toFloat(),
            mPaint!!,
            Canvas.ALL_SAVE_FLAG
        )
        //先绘制子控件
        super.dispatchDraw(canvas)
        //使用path构建四个圆角
        mPath.apply {
            addRect(mContentRF!!, Path.Direction.CW)
            addRoundRect(mContentRF!!, mCornerRadius, mCornerRadius, Path.Direction.CW)
            fillType = Path.FillType.EVEN_ODD
        }
        //使用xfermode在图层上进行合成，处理圆角
        mPaint?.xfermode = mXfermode
        canvas.drawPath(mPath, mPaint!!)
        utilReset(mPaint!!, null, 0)
        mPath.reset()

        canvas.restore()
    }

    private fun helpGreenCurtain(canvas: Canvas, debug: Boolean) {
        if (debug) {
            canvas.drawColor(Color.GREEN)
        }
    }

    private fun initAttrs(context: Context, attrs: AttributeSet?) {
        val a = context.obtainStyledAttributes(attrs, R.styleable.ShadowLayout)
        mShadowColor = a.getColor(R.styleable.ShadowLayout_shadowColor, DEFAULT_SHADOW_COLOR)
        mShadowRadius = a.getDimensionPixelSize(R.styleable.ShadowLayout_shadowRadius, 0).toFloat()
        mDx = a.getDimensionPixelSize(R.styleable.ShadowLayout_shadowDx, 0).toFloat()
        mDy = a.getDimensionPixelSize(R.styleable.ShadowLayout_shadowDy, 0).toFloat()
        mCornerRadius = a.getDimensionPixelSize(R.styleable.ShadowLayout_shadowCorner, 0).toFloat()
        mBorderColor =
            a.getColor(R.styleable.ShadowLayout_shadowBorderColor, DEFAULT_BORDER_COLOR)
        mBorderWidth =
            a.getDimensionPixelSize(R.styleable.ShadowLayout_shadowBorderWidth, 0).toFloat()
        mShadowSides = a.getInt(R.styleable.ShadowLayout_shadowSides, FLAG_SIDES_ALL)
        a.recycle()
    }

    private fun init() {
        mXfermode = PorterDuffXfermode(PorterDuff.Mode.DST_OUT)
        val xPadding: Int = (mShadowRadius + abs(mDx)).toInt()
        val yPadding: Int = (mShadowRadius + abs(mDy)).toInt()
        val pl = if (containsFlag(mShadowSides, FLAG_SIDES_LEFT)) xPadding else 0
        val pt = if (containsFlag(mShadowSides, FLAG_SIDES_TOP)) yPadding else 0
        val pr = if (containsFlag(mShadowSides, FLAG_SIDES_RIGHT)) xPadding else 0
        val pb = if (containsFlag(mShadowSides, FLAG_SIDES_BOTTOM)) yPadding else 0
        setPadding(pl, pt, pr, pb)
        setLayerType(View.LAYER_TYPE_SOFTWARE, null)

        mPaint = Paint()
        utilReset(mPaint!!, null, Color.WHITE)

        mHelpPaint = Paint()
        utilReset(mHelpPaint!!, null, Color.RED)

    }

    private fun containsFlag(sides: Int, flag: Int): Boolean {
        return sides or flag == sides
    }

    private fun utilReset(paint: Paint, colorString: String?, @ColorInt color: Int) {
        paint.reset()
        //这里默认值使用白色，可处理掉系统渲染抗锯齿时，人眼可观察到像素颜色
        var paintColor = Color.WHITE
        if (color != 0) {
            paintColor = color
        } else if (!TextUtils.isEmpty(colorString)) {
            paintColor = Color.parseColor(colorString)
        }
        paint.color = paintColor
        paint.isAntiAlias = true
        paint.style = Paint.Style.FILL
        paint.strokeWidth = 0f
    }
}